package com.wzdigit.wms.wms.service.inv;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wzdigit.framework.Shift;
import com.wzdigit.mes.basic.api.BasicSimpleCodeRuleApi;
import com.wzdigit.wms.basic.client.Pager;
import com.wzdigit.wms.basic.client.PagerInfo;
import com.wzdigit.wms.basic.client.request.inv.SearchSealHeaderRequest;
import com.wzdigit.wms.basic.client.request.inv.UnSealGoodsRequest;
import com.wzdigit.wms.basic.client.response.Result;
import com.wzdigit.wms.basic.client.response.inv.QualifiedGoodsResponse;
import com.wzdigit.wms.basic.client.response.inv.SealDtlGoodsResponse;
import com.wzdigit.wms.basic.client.response.inv.SealDtlResponse;
import com.wzdigit.wms.basic.client.response.inv.SealHeaderResponse;
import com.wzdigit.wms.basic.domain.basic.Sku;
import com.wzdigit.wms.basic.domain.dtos.inventory.UpdateInventoryInputDto;
import com.wzdigit.wms.basic.domain.inv.SealDtl;
import com.wzdigit.wms.basic.domain.inv.SealDtlGoods;
import com.wzdigit.wms.basic.domain.inv.SealHeader;
import com.wzdigit.wms.basic.domain.inventory.Lotno;
import com.wzdigit.wms.basic.enums.QaStatusEnum;
import com.wzdigit.wms.basic.enums.SealFlagEnum;
import com.wzdigit.wms.basic.enums.SealTypeEnum;
import com.wzdigit.wms.basic.mapper.core.basic.SkuMapper;
import com.wzdigit.wms.basic.mapper.core.inv.SealDtlGoodsMapper;
import com.wzdigit.wms.basic.mapper.core.inv.SealDtlMapper;
import com.wzdigit.wms.basic.mapper.core.inv.SealHeaderMapper;
import com.wzdigit.wms.basic.mapper.core.inventory.GoodsMapper;
import com.wzdigit.wms.basic.util.HttpSessionUtil;
import com.wzdigit.wms.basic.service.code.InventoryService;
import com.wzdigit.wms.basic.service.code.LotnoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 解封-服务类
 * @author yangdongjie
 * @GdnService.java
 * @2021年2月24日下午3:25:03
 */
@Service
@Slf4j
public class UnSealGoodsService {
	
	@Autowired
	private SkuMapper skuMapper;

	@Autowired
	private GoodsMapper goodsMapper;
	
	@Autowired
	private SealDtlMapper sealDtlMapper;
	
	@Autowired
	private SealHeaderMapper sealHeaderMapper;
	
	@Autowired
	private SealDtlGoodsMapper sealDtlGoodsMapper;
	
	@Autowired
	private LotnoService lotnoService;
	
	@Autowired
	private InventoryService inventoryService;
	
	@Reference(version = "${dubbo.consumers.basic.simple.code.rule.api:1.0.0}", check = false)
	private BasicSimpleCodeRuleApi basicSimpleCodeRuleApi;
	
	/**
	 * 【解封主档数据】输出
	 * @param dto
	 * @param pager
	 * @return
	 */
	public PagerInfo<List<SealHeaderResponse>> searchSealHeader(SearchSealHeaderRequest dto, Pager<?> pager) {
		if(dto.getSealType() == null) {
			dto.setSealType(SealTypeEnum.SEAL.code);
		}
    	Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
    	PagerInfo<List<SealHeaderResponse>> pagerInfo = new PagerInfo<>();
    	List<SealHeaderResponse> list = sealHeaderMapper.selectAll(dto);
    	pagerInfo.setTotalCount(page.getTotal());
    	pagerInfo.setItems(list);
		return pagerInfo;
    }
	
	/**
	 * 【解封明细数据】输出
	 * @param sealHeaderId
	 * @return
	 */
	public List<SealDtlResponse> searchSealDtl(Integer sealHeaderId) {
		List<SealDtlResponse> list = sealDtlMapper.selectBySealHeaderId(sealHeaderId);
		return list;
    }
	
	/**
	 * 【解封SN数据】输出
	 * @param sealDtlId
	 * @param pager
	 * @return
	 */
	public PagerInfo<List<SealDtlGoodsResponse>> searchSealDtlGoods(Integer sealDtlId, Pager<?> pager) {
    	Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
        PagerInfo<List<SealDtlGoodsResponse>> pagerInfo = new PagerInfo<>();
        
        List<SealDtlGoodsResponse> list = sealDtlGoodsMapper.selectBySealDtlId(sealDtlId);
        pagerInfo.setTotalCount(page.getTotal());
        pagerInfo.setItems(list);
		return pagerInfo;
    }
	
	/**
	 * 解封
	 * 
	 * @param dto
	 * @param servletRequest
	 * @return
	 * @throws SecurityException 
	 * @throws NoSuchMethodException 
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public synchronized Result<String> unSealGoods(UnSealGoodsRequest dto, HttpServletRequest servletRequest) throws Exception {
		List<Integer> items = dto.getItems();
		Map<Integer, List<Integer>> map = new HashMap<>();
		List<QualifiedGoodsResponse> list1 = new ArrayList<>();
		List<List<QualifiedGoodsResponse>> list2 = new ArrayList<>();
		for (Integer sealDtlId : items) {
			List<Integer> goodsIdList = sealDtlGoodsMapper.selectGoodsIdBySealDtlId(sealDtlId);
			List<QualifiedGoodsResponse> goodsList = goodsMapper.selectQualifiedGoods(null, QaStatusEnum.NG.code, goodsIdList);
			goodsIdList = goodsList.stream().map(g -> g.getGoodsId()).collect(Collectors.toList());
			
			map.put(sealDtlId, goodsIdList);
			list1.addAll(goodsList);
			list2.add(goodsList);
		}
		
		// 检验1
		if (list1.size() == 0) {
			Shift.fatal("没有可解封数据！");
		}
		// 检验2
		int size = list1.stream().collect(Collectors.groupingBy(t -> (t.getFactory() + "#" + t.getOwner()), Collectors.toList())).size();
		if (size > 1) {
			Shift.fatal("勾选的解封信息，必须都相同“组织”，“货主”才允许生成封库单！");
		}

		String loginName = HttpSessionUtil.getLoginName(servletRequest);
		Date date = new Date();

		Class<SealDtl> sealDtlClass = SealDtl.class;
		Class<Lotno> lotnoClass = Lotno.class;

		// 解封单单据号
		String simpleCodeRule = "JK";
		String sealNo = basicSimpleCodeRuleApi.GenerateCode(simpleCodeRule);

		// 解封单表头
		SealHeader sealHeader = new SealHeader();
		sealHeader.setSealNo(sealNo);
		sealHeader.setSealType(SealTypeEnum.UN_SEAL.code);
		sealHeader.setFactory(list1.get(0).getFactory());
		sealHeader.setOwner(list1.get(0).getOwner());
		sealHeader.setReason(dto.getReason());
		sealHeader.setSealTime(date);
		sealHeader.setSealUser(loginName);
		sealHeader.setCreateTime(date);
		sealHeader.setCreateUser(loginName);
		sealHeaderMapper.insert(sealHeader);

		int lineNo = 0;
		for (int i = 0; i < items.size(); i++) {
			List<QualifiedGoodsResponse> goodsItemList = list2.get(i);
			if(goodsItemList.size() == 0) {
				continue;
			}
			SealDtl dtl = sealDtlMapper.selectById(items.get(i));
			Map<String, List<QualifiedGoodsResponse>> goodsMap = goodsItemList.stream().collect(Collectors.groupingBy(g -> 
				(g.getWhsId() + "#" + g.getZoneId() + "#" + g.getFactory()+ "#" + g.getOwner() + "#" +
						g.getSkuId() + "#" + g.getInspNo() + "#" + g.getPrdWo()+ "#" + g.getPoNo() + "#" +
						g.getSoNo() + "#" + g.getSoItem() + "#" + g.getLotno()), Collectors.toList()));
			for (String key : goodsMap.keySet()) {
				List<QualifiedGoodsResponse> goodsList = goodsMap.get(key);
				QualifiedGoodsResponse item = goodsList.get(0);
				
				Sku sku = skuMapper.selectById(item.getSkuId());

				SealDtl sealDtl = new SealDtl();
				sealDtl.setSealHeaderId(sealHeader.getSealHeaderId());
				sealDtl.setSealNo(sealNo);
				sealDtl.setSourceNo(dtl.getSealNo());
				sealDtl.setSourceLineNo(String.valueOf(dtl.getSealLineNo()));
				sealDtl.setSealLineNo(++lineNo);
				sealDtl.setSkuId(item.getSkuId());
				sealDtl.setQaStatus(QaStatusEnum.OK.code);
				sealDtl.setLotno(item.getLotno());
				sealDtl.setSoNo(item.getSoNo());
				sealDtl.setSoLineNo(item.getSoItem());
				sealDtl.setPoNo(item.getPoNo());
				sealDtl.setPrdWo(item.getPrdWo());
				sealDtl.setWhsId(item.getWhsId());
				sealDtl.setZoneId(item.getZoneId());
				sealDtl.setInspNo(item.getInspNo());
				sealDtl.setCustomerModle(sku.getModel());
				sealDtl.setUnit(sku.getBaseUnit());
				sealDtl.setSealQty(BigDecimal.ZERO);
				sealDtl.setUnsealQty(new BigDecimal(goodsList.size()));
				sealDtl.setStatus(1);
				sealDtl.setCreateTime(date);
				sealDtl.setCreateUser(loginName);
				sealDtlMapper.insert(sealDtl);

				// 获取设置批次号及属性
				Lotno lotno = lotnoService.getLotnoBySealDtlId(sealDtl.getSealDtlId());
				if (lotno != null) {
					sealDtl.setLotno(lotno.getLotno());
					for (int j = 1; j < 13; j++) {
						Field lotnoField = lotnoClass.getDeclaredField("lotAttr" + j);
						lotnoField.setAccessible(true);
						Object lotnoFieldValue = lotnoField.get(lotno);

						Method setLotAttr = sealDtlClass.getMethod("setLotAttr" + j, String.class);
						setLotAttr.setAccessible(true);
						setLotAttr.invoke(sealDtl, lotnoFieldValue == null ? null : lotnoFieldValue.toString());
					}
					sealDtlMapper.updateById(sealDtl);
				}
				
				// 封库单明细SN
				for (QualifiedGoodsResponse goods : goodsList) {
					SealDtlGoods sealDtlGoods = new SealDtlGoods();
					sealDtlGoods.setSealDtlId(sealDtl.getSealDtlId());
					sealDtlGoods.setGoodsSn(goods.getGoodsSn());
					sealDtlGoods.setGoodsId(goods.getGoodsId());
					sealDtlGoods.setQty(goods.getQty());
					sealDtlGoods.setStatus(goods.getStatus());
					sealDtlGoods.setSealFlag(SealFlagEnum.UN_SEAL.code);
					sealDtlGoods.setCreateTime(date);
					sealDtlGoods.setCreateUser(loginName);
					sealDtlGoodsMapper.insert(sealDtlGoods);
				}
			}
			List<Integer> goodsIdList = goodsItemList.stream().map(g -> g.getGoodsId()).collect(Collectors.toList());
			sealDtlGoodsMapper.updateSealFlag(SealFlagEnum.UN_SEAL.code, loginName, dtl.getSealDtlId(), goodsIdList);
			sealDtlMapper.updateUnsealQty(dtl.getSealDtlId(), goodsIdList.size(), loginName);
			goodsMapper.batchUpdateQaStatus(QaStatusEnum.OK.code, loginName, goodsIdList);
		}
		
		// 更新库存和sn状态
		Map<String, List<QualifiedGoodsResponse>> zoneIdInvMap = list1.stream().collect(
				Collectors.groupingBy(g -> (g.getWhsId() + "#" + g.getOwner() + "#" + g.getSkuId() + "#" + 
					g.getFactory() + "#" + g.getLotno() + "#" + g.getVendorId() + "#" + g.getInvAttr() + "#" + 
					g.getQaStatus() + "#" + g.getUnit() + "#" + g.getZoneId()), Collectors.toList()));
		Map<String, List<QualifiedGoodsResponse>> locIdInvMap = list1.stream().collect(
				Collectors.groupingBy(g -> (g.getWhsId() + "#" + g.getOwner() + "#" + g.getSkuId() + "#" + 
					g.getFactory() + "#" + g.getLotno() + "#" + g.getVendorId() + "#" + g.getInvAttr() + "#" + 
					g.getQaStatus() + "#" + g.getUnit() + "#" + g.getLocId()), Collectors.toList()));
		// 库区库存
		for (String zoneIdInvKey : zoneIdInvMap.keySet()) {
			List<QualifiedGoodsResponse> zoneIdInvList = zoneIdInvMap.get(zoneIdInvKey);
			QualifiedGoodsResponse zoneIdInv = zoneIdInvList.get(0);
			
			UpdateInventoryInputDto input = new UpdateInventoryInputDto();
			input.setWhsId(zoneIdInv.getWhsId());
			input.setOwner(zoneIdInv.getOwner());
			input.setSkuId(zoneIdInv.getSkuId());
			input.setFactory(zoneIdInv.getFactory());
			input.setLotNo(zoneIdInv.getLotno());
			input.setVendorId(zoneIdInv.getVendorId());
			input.setInvAttr(zoneIdInv.getInvAttr());
			input.setQaStatus(zoneIdInv.getQaStatus());
			input.setUnit(zoneIdInv.getUnit());
			input.setZoneId(zoneIdInv.getZoneId());
			input.setQty(new BigDecimal(zoneIdInvList.size()).negate());
			input.setOperator(loginName);
			// 减少不合格的库存
			inventoryService.updateZoneInventory(input);
			
			input.setQaStatus(QaStatusEnum.OK.code);
			input.setQty(input.getQty().abs());
			// 增加合格的库存
			inventoryService.updateZoneInventory(input);
		}
		for (String locIdInvKey : locIdInvMap.keySet()) {
			List<QualifiedGoodsResponse> locIdInvList = locIdInvMap.get(locIdInvKey);
			QualifiedGoodsResponse locIdInv = locIdInvList.get(0);
			
			UpdateInventoryInputDto input = new UpdateInventoryInputDto();
			input.setWhsId(locIdInv.getWhsId());
			input.setOwner(locIdInv.getOwner());
			input.setSkuId(locIdInv.getSkuId());
			input.setFactory(locIdInv.getFactory());
			input.setLotNo(locIdInv.getLotno());
			input.setVendorId(locIdInv.getVendorId());
			input.setInvAttr(locIdInv.getInvAttr());
			input.setQaStatus(locIdInv.getQaStatus());
			input.setUnit(locIdInv.getUnit());
			input.setLocId(locIdInv.getLocId());
			input.setQty(new BigDecimal(locIdInvList.size()).negate());
			input.setOperator(loginName);
			// 减少不合格的库存
			inventoryService.updateLocInventroy(input);
			
			input.setQaStatus(QaStatusEnum.OK.code);
			input.setQty(input.getQty().abs());
			// 增加合格的库存
			inventoryService.updateLocInventroy(input);
		}
		return new Result<String>(sealNo);
	}
}